HEX
Server: Apache/2.4.68 (Debian)
System: Linux as-cs-widget-demo-us-central1 6.1.0-44-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.164-1 (2026-03-09) x86_64
User: root (0)
PHP: 8.2.32
Disabled: NONE
Upload Files
File: /var/www/kevin-demo/wp-content/plugins/grocerslist/includes/Service/UrlMappingService.php
<?php

namespace GrocersList\Service;

use GrocersList\Database\UrlMappingTable;
use GrocersList\Support\LinkExtractor;
use GrocersList\Support\LinkUtils;

class UrlMappingService
{
    static function reset_mappings(): void
    {
        $table = new UrlMappingTable();
        $table->truncate_table();
    }

    static function get_link_count_info(): array
    {
        global $wpdb;

        $table = new UrlMappingTable();

        $posts_with_links = 0;
        $total_amazon_links = 0;
        $total_mapped_links = 0;
        $total_unmapped_links = 0;

        // Get all published posts with content // TODO: do we want to run for unpublished posts too?
        $posts = $wpdb->get_results(
            "SELECT ID, post_content
             FROM {$wpdb->posts}
             WHERE post_status = 'publish'
               AND post_type IN ('post', 'page')
               AND post_content IS NOT NULL
               AND post_content != ''"
        );

        foreach ($posts as $post) {
            $content = $post->post_content;
            $normalized = html_entity_decode(stripslashes($content)); // *CRITICAL - hash will not match DB row if url is not normalized first
            $amazon_links = LinkExtractor::extractUnrewrittenLinks($normalized);

            if (!empty($amazon_links)) {
                $total_amazon_links += count($amazon_links);;

                $existing_mappings = $table->get_mappings_by_urls($amazon_links);
                $total_mapped_links += count($existing_mappings);

                $unmapped_links = array_values(array_diff($amazon_links, array_keys($existing_mappings)));
                $unmapped_links_count = count($unmapped_links);

                if ($unmapped_links_count > 0) {
                    $posts_with_links++;
                    // $total_amazon_links is NOT unique, so we cannot simply subtract mapped links from the total:
                    $total_unmapped_links += $unmapped_links_count;
                }
            }
        }

        return [
            // posts
            'totalPosts' => count($posts),
            'postsWithLinks' => $posts_with_links,
            // links
            'totalAmazonLinks' => $total_amazon_links,
            'totalMappedLinks' => $total_mapped_links,
            'totalUnmappedLinks' => $total_unmapped_links,
        ];
    }

    static function create_url_mappings_batch(array $urls, int $post_id = 0): array
    {
        if (empty($urls)) {
            return [];
        }

        $table = new UrlMappingTable();

        // Check which URLs we already have mappings for
        $existing_mappings = $table->get_mappings_by_urls($urls);
        // Use array_values to reset keys after array_diff
        $missing_urls = array_values(array_diff($urls, array_keys($existing_mappings)));

        // Fetch new mappings for missing URLs
        if (!empty($missing_urls)) {
            $response = ApiClient::postAppLinks($missing_urls);

            $new_mappings = [];

            foreach ($response->successes as $item) {
                $original_url = html_entity_decode($item->url);
                $linksta_url = LinkUtils::buildLinkstaUrl($item->hash);
                
                $new_mappings[$original_url] = [
                    'linksta_url' => $linksta_url,
                    'link_hash' => $item->hash,
                    'post_id' => $post_id
                ];
            }

            // Store new mappings in database
            if (!empty($new_mappings)) {
                $table->upsert_mappings($new_mappings);
            }

            // Merge with existing mappings
            foreach ($new_mappings as $url => $data) {
                $existing_mappings[$url] = (object)[
                    'linksta_url' => $data['linksta_url'],
                    'link_hash' => $data['link_hash'],
                    'created_at' => date('Y-m-d H:i:s')
                ];
            }
        }

        return $existing_mappings;
    }

    static function get_url_mappings_for_content(string $content): array
    {
        $table = new UrlMappingTable();
        $normalized = html_entity_decode(stripslashes($content));
        $urls = LinkExtractor::extract($normalized);

        if (empty($urls)) {
            return [];
        }

        return $table->get_mappings_by_urls($urls);
    }
}